package io.github.annyylxyms.gyncache.core;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.Arrays;

/**
 * 自写返回改为了String
 * @author Anny
 * @date 2024/12/31 14:36
 */
public class GynCacheHandler extends SimpleChannelInboundHandler<String> {
    //回车换行,报文结束一定要加的片段
    private static final String CRLF = "\r\n";
    private static final String STRING_PREFIX = "+";
    private static final String BULK_PREFIX = "$";
    private static final String OK = "OK";
    //踩坑！注意数据本身最后要有个换行！输出统计$字符数时才准确
    private static final String INFO = "GynCache server[v1.0.0], created by Anny." + CRLF
            + "Mock Redis Server, at 2024-12-31 in Shanghai." + CRLF;

    public static final GynCache cache = new GynCache();


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
        //把回车换行去掉，竖着输出变成一行输出
        String[] args = message.split(CRLF);
        System.out.println("GynCacheHandler =>" + String.join(",", args));
        String cmd = args[2].toUpperCase();
        Command command = Commands.get(cmd);
        if (command != null) {
            try {
                Reply<?> reply = command.exec(cache, args);
                System.out.println("CMD[" + cmd + "]=>" + reply.type + ":" + reply.value);
                replyContext(ctx, reply);
            } catch (Exception exception) {
                Reply<?> reply = Reply.error("EXP exception with msg: '" + exception.getMessage() + "'");
                replyContext(ctx, reply);
            }
        } else {
            Reply<?> reply = Reply.error("ERR unsupported command '" + cmd + "'");
            replyContext(ctx, reply);
        }

        /*if ("COMMAND".equals(cmd)) {
            //返回一个数组：
            writeByteBuf(ctx, "*2"
                    + CRLF + "$7"
                    + CRLF + "COMMAND"
                    + CRLF + "$4"
                    + CRLF + "PING"
                    + CRLF);
        } else if ("PING".equals(cmd)) {
            String ret = "PONG";
            if (args.length >= 5) {
                ret = args[4];
            }
            simpleString(ctx, ret);
        } else if ("INFO".equals(cmd)) {
            //复杂字符串以$开头
            bulkString(ctx, INFO);
        } else if ("SET".equals(cmd)) {
            //set a 100
            //    *3
            //    $3
            //    set
            //    $1
            //    a
            //    $3
            //    100
            cache.set(args[4], args[6]);
            simpleString(ctx, OK);
        } else if ("GET".equals(cmd)) {
            //get a
            //*2
            //$3
            //get
            //$1
            //a
            //这里的args[4]是上面list里的第4个参数，也就是key a的位置！
            String value = cache.get(args[4]);
            bulkString(ctx, value);
        } else if ("STRLEN".equals(cmd)) {
            //strlen a
            //*2
            //$6
            //strlen
            //$1
            //a
            String value = cache.get(args[4]);
            integer(ctx, value == null ? 0 : value.length());
        } else if ("DEL".equals(cmd)) {
            //del a b c
            //*4
            //$3
            //del
            //$1
            //a
            //$1
            //b
            //$1
            //c
            //这里计算的是删除的key的个数
            int len = (args.length - 3) / 2;
            String[] keys = new String[len];
            for (int i = 0; i < len; i++) {
                keys[i] = args[4 + i * 2];
            }
            //从第四个位置起每隔一个就是一个待删除的key
            int del = cache.del(keys);
            integer(ctx, del);
        } else if ("EXISTS".equals(cmd)) {
            //exists a b c
            int len = (args.length - 3) / 2;
            String[] keys = new String[len];
            for (int i = 0; i < len; i++) {
                keys[i] = args[4 + i * 2];
            }
            integer(ctx, cache.exists(keys));
        } else if ("MGET".equals(cmd)) {
            // mget a c d
            int len = (args.length - 3) / 2;
            String[] keys = new String[len];
            for (int i = 0; i < len; i++) {
                keys[i] = args[4 + i * 2];
            }
            //返回的是数组
            array(ctx, cache.mget(keys));
        } else if ("MSET".equals(cmd)) {
            //mset a 1 b 2 c 3
            //*6
            //$4
            //mset

            //$1
            //a
            //$1
            //1

            //$1
            //b
            //$1
            //2

            //$1
            //c
            //$1
            //3
            //这里就是像上面注释一样，用间隔的4行去计数
            int len = (args.length - 3) / 4;
            String[] keys = new String[len];
            String[] vals = new String[len];
            for (int i = 0; i < len; i++) {
                //keys从第4个开始取，每4个拿一次，vals从第6个开始，每4个拿一次
                keys[i] = args[4 + i * 4];
                vals[i] = args[6 + i * 4];
            }
            cache.mset(keys, vals);

            simpleString(ctx, OK);
        } else if ("INCR".equals(cmd)) {
            //+1
            String key = args[4];
            try {
                integer(ctx, cache.incr(key));
            } catch (NumberFormatException nfe) {
                error(ctx, "NFE " + key + " value[" + cache.get(key) + "] is not integer.");
            }
        } else if ("DECR".equals(cmd)) {
            //-1
            String key = args[4];
            try {
                integer(ctx, cache.decr(key));
            } catch (NumberFormatException nfe) {
                error(ctx, "NFE " + key + " value [" + cache.get(key) + "]is not integer.");
            }
        } else {
            simpleString(ctx, OK);
        }*/
    }

    private void replyContext(ChannelHandlerContext ctx, Reply<?> reply) {
        switch (reply.getType()) {
            case INT:
                integer(ctx, (Integer) reply.getValue());
                break;
            case ERROR:
                error(ctx, (String) reply.getValue());
                break;
            case SIMPLE_STRING:
                simpleString(ctx, (String) reply.getValue());
                break;
            case BULK_STRING:
                bulkString(ctx, (String) reply.getValue());
                break;
            case ARRAY:
                array(ctx, (String[]) reply.getValue());
                break;
            default:
                simpleString(ctx, OK);
        }
    }

    private static String errorEncode(String msg) {
        //(error)是减号开头
        return "-" + msg + CRLF;
    }

    private void error(ChannelHandlerContext ctx, String msg) {
        writeByteBuf(ctx, errorEncode(msg));
    }

    private static String arrayEncode(Object[] array) {
        //数组可以是不同类型，可以支持嵌套
        StringBuilder sb = new StringBuilder();
        if (array == null) {
            sb.append("*-1" + CRLF);
        } else if (array.length == 0) {
            sb.append("*0" + CRLF);
        } else {
            sb.append("*" + array.length + CRLF);
            for (int i = 0; i < array.length; i++) {
                Object obj = array[i];
                if (obj == null) {
                    sb.append("$-1" + CRLF);
                } else {
                    if (array[i] instanceof Integer) {
                        sb.append(integerEncode((Integer) obj));
                    } else if (array[i] instanceof String) {
                        sb.append(bulkStringEncode((String) obj));
                    } else if (array[i] instanceof Object[] objs) {
                        //循环嵌套的数组递归调用
                        sb.append(arrayEncode(objs));
                    }
                }
            }
        }
        return sb.toString();
    }

    private void array(ChannelHandlerContext ctx, String[] array) {
        writeByteBuf(ctx, arrayEncode(array));
    }

    private static String integerEncode(int i) {
        return ":" + i + CRLF;
    }

    private void integer(ChannelHandlerContext ctx, int i) {
        writeByteBuf(ctx, integerEncode(i));
    }


    private void bulkString(ChannelHandlerContext ctx, String content) {
        writeByteBuf(ctx, bulkStringEncode(content));
    }

    private static String bulkStringEncode(String content) {
        String ret;
        if (content == null) {
            //对象为空null
            ret = "$-1";
        } else if (content.isEmpty()) {
            //字符串为空→""
            ret = "$0";
        } else {
            ret = BULK_PREFIX + content.getBytes().length + CRLF + content;
        }
        return ret + CRLF;
    }

    private void simpleString(ChannelHandlerContext ctx, String content) {
        writeByteBuf(ctx, simpleStringEncode(content));
    }

    private static String simpleStringEncode(String content) {
        String ret;
        if (content == null) {
            //对象为空null
            ret = "$-1";
        } else if (content.isEmpty()) {
            //字符串为空→""
            ret = "$0";
        } else {
            ret = STRING_PREFIX + content;
        }
        return ret + CRLF;
    }

    private void writeByteBuf(ChannelHandlerContext ctx, String content) {
        System.out.println("wrap byte buffer and reply" + content);
        ByteBuf buffer = Unpooled.buffer(128);
        buffer.writeBytes(content.getBytes());
        ctx.writeAndFlush(buffer);
    }
}
